package org.dromara.system.util;

import cn.hutool.core.lang.Pair;
import org.dromara.system.enums.TimeRadiusEnum;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @date 2018/7/16
 **/
public class TimeUtil {

    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYY_MM = "yyyy-MM";
    /**
     * 默认日期格式
     */
    public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    /**
     * 默认日期格式
     */
    public static final DateTimeFormatter DEFAULT_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_PATTERN);
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault();

    /**
     * LocalDateTime 转 字符串，指定日期格式
     *
     * @param localDateTime
     * @param pattern
     * @return
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        String timeStr = formatter.format(localDateTime.atZone(DEFAULT_ZONE_ID));
        return timeStr;
    }

    /**
     * Date 转 字符串, 指定日期格式
     *
     * @param time
     * @param pattern
     * @return
     */
    public static String format(Date time, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        String timeStr = formatter.format(time.toInstant().atZone(DEFAULT_ZONE_ID));
        return timeStr;
    }

    /**
     * Date 转 字符串，默认日期格式
     *
     * @param time
     * @return
     */
    public static String format(Date time) {

        String timeStr = DEFAULT_DATE_TIME_FORMATTER.format(time.toInstant().atZone(DEFAULT_ZONE_ID));
        return timeStr;
    }

    /**
     * timestamp 转 字符串，默认日期格式
     *
     * @param timestamp
     * @return
     */
    public static String format(long timestamp) {
        String timeStr = DEFAULT_DATE_TIME_FORMATTER.format(new Date(timestamp).toInstant().atZone(DEFAULT_ZONE_ID));
        return timeStr;
    }

    /**
     * 字符串 转 Date
     *
     * @param time
     * @return
     */
    public static Date strToDate(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, DEFAULT_DATE_TIME_FORMATTER);
        return Date.from(localDateTime.atZone(DEFAULT_ZONE_ID).toInstant());

    }

    /**
     * 获取当天剩余的秒数
     *
     * @param currentDate
     * @return
     */
    public static Integer getRemainSecondsOneDay(Date currentDate) {
        LocalDateTime midnight = LocalDateTime.ofInstant(currentDate.toInstant(), ZoneId.systemDefault()).plusDays(1)
                .withHour(0).withMinute(0).withSecond(0).withNano(0);

        LocalDateTime currentDateTime = LocalDateTime.ofInstant(currentDate.toInstant(), ZoneId.systemDefault());
        long seconds = ChronoUnit.SECONDS.between(currentDateTime, midnight);
        return (int) seconds;
    }

    /**
     * 获取时间范围
     *
     * @param
     * @return Pair<LocalDateTime, LocalDateTime>
     * @author 王星
     * @date 2024-06-14 11:18:45
     */
    public static Pair<LocalDateTime, LocalDateTime> getTimeRadius(TimeRadiusEnum timeRadiusEnum) {
        LocalDate currentDate = LocalDate.now();
        Pair<LocalDateTime, LocalDateTime> pair = null;
        switch (timeRadiusEnum) {
            case TODAY:
                LocalDateTime startOfToday = LocalDateTime.of(currentDate, LocalTime.MIN);
                LocalDateTime endOfToday = LocalDateTime.of(currentDate, LocalTime.MAX);
                pair = new Pair<>(startOfToday, endOfToday);
                break;
            case YESTERDAY:
                LocalDateTime startOfYesterday = LocalDateTime.of(currentDate.minusDays(1), LocalTime.MIN);
                LocalDateTime endOfYesterday = LocalDateTime.of(currentDate.minusDays(1), LocalTime.MAX);
                pair = new Pair<>(startOfYesterday, endOfYesterday);
                break;
            case SEVEN_TODAY:
                LocalDate sevenDaysAgo = currentDate.minusDays(6);
                LocalDateTime startOfTodaySeven = LocalDateTime.of(sevenDaysAgo, LocalTime.MIN);
                LocalDateTime endOfTodaySeven = LocalDateTime.of(currentDate, LocalTime.MAX);
                pair = new Pair<>(startOfTodaySeven, endOfTodaySeven);
                break;
            case LAST_MONTH:
                LocalDate firstDayOfLastMonth = currentDate.minusMonths(1).withDayOfMonth(1);
                LocalDate lastDayOfLastMonth = currentDate.minusMonths(1)
                        .withDayOfMonth(currentDate.minusMonths(1).lengthOfMonth());
                LocalDateTime startOfLastMonth = LocalDateTime.of(firstDayOfLastMonth, LocalTime.MIN);
                LocalDateTime endOfLastMonth = LocalDateTime.of(lastDayOfLastMonth, LocalTime.MAX);
                pair = new Pair<>(startOfLastMonth, endOfLastMonth);
                break;
            case LAST_TWO_MONTH:
                LocalDate firstDayOfLastTwoMonth = currentDate.minusMonths(2).withDayOfMonth(1);
                LocalDate lastDayOfLastTwoMonth = currentDate.minusMonths(2)
                        .withDayOfMonth(currentDate.minusMonths(1).lengthOfMonth());
                LocalDateTime startOfLastTwoMonth = LocalDateTime.of(firstDayOfLastTwoMonth, LocalTime.MIN);
                LocalDateTime endOfLastTwoMonth = LocalDateTime.of(lastDayOfLastTwoMonth, LocalTime.MAX);
                pair = new Pair<>(startOfLastTwoMonth, endOfLastTwoMonth);
                break;
            case CURRENT_MONTH:
                LocalDate firstDayOfMonth = currentDate.withDayOfMonth(1);
                LocalDate lastDayOfMonth = currentDate.withDayOfMonth(currentDate.lengthOfMonth());
                LocalDateTime startOfMonth = LocalDateTime.of(firstDayOfMonth, LocalTime.MIN);
                LocalDateTime endOfMonth = LocalDateTime.of(lastDayOfMonth, LocalTime.MAX);
                pair = new Pair<>(startOfMonth, endOfMonth);
                break;
            case HALF_YEAR:
                LocalDate halfYearAgoTime = currentDate.plusMonths(-5);
                LocalDateTime startOfTodayHalf = LocalDateTime.of(halfYearAgoTime, LocalTime.MIN);
                LocalDateTime endOfTodayHalf = LocalDateTime.of(currentDate, LocalTime.MAX);
                pair = new Pair<>(startOfTodayHalf, endOfTodayHalf);
                break;
            case YEAR:
                int year = currentDate.getYear();
                // 当前年份的开始时间
                LocalDateTime startOfYear = LocalDateTime.of(year, 1, 1, 0, 0);

                // 当前年份的结束时间
                LocalDateTime endOfYear = LocalDateTime.of(year, 12, 31, 23, 59).withMinute(59)
                        .withSecond(59);
                pair = new Pair<>(startOfYear, endOfYear);
                break;
            default:
                break;
        }
        return pair;
    }


    public static List<LocalDateTime> getHoursBetween(LocalDateTime startDate, LocalDateTime endDate) {
        long numOfDaysBetween = ChronoUnit.HOURS.between(startDate, endDate) + 1;
        return IntStream.iterate(0, i -> i + 1)
                .limit(numOfDaysBetween)
                .mapToObj(startDate::plusHours)
                .collect(Collectors.toList());
    }

    public static List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
        long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1;
        return IntStream.iterate(0, i -> i + 1)
                .limit(numOfDaysBetween)
                .mapToObj(startDate::plusDays)
                .collect(Collectors.toList());
    }

    public static List<LocalDate> getMonthsBetween(LocalDate startDate, LocalDate endDate) {
        long numOfDaysBetween = ChronoUnit.MONTHS.between(startDate, endDate) + 1;
        return IntStream.iterate(0, i -> i + 1)
                .limit(numOfDaysBetween)
                .mapToObj(startDate::plusMonths)
                .collect(Collectors.toList());
    }

    public static List<LocalDate> getYearsBetween(LocalDate startDate, LocalDate endDate) {
        long numOfDaysBetween = ChronoUnit.YEARS.between(startDate, endDate) + 1;
        return IntStream.iterate(0, i -> i + 1)
                .limit(numOfDaysBetween)
                .mapToObj(startDate::plusYears)
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        Pair<LocalDateTime, LocalDateTime> timeRadius = getTimeRadius(TimeRadiusEnum.YESTERDAY);
        System.out.println(timeRadius.getKey() + "--" + timeRadius.getValue());
    }
}
